package com.gxa.hualianeshop.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxa.hualianeshop.common.base.ResultCode;
import com.gxa.hualianeshop.common.exception.BizException;
import com.gxa.hualianeshop.common.util.SnowFlake;
import com.gxa.hualianeshop.entity.dto.OrderDto;
import com.gxa.hualianeshop.entity.pojo.*;
import com.gxa.hualianeshop.mapper.OrderMapper;
import com.gxa.hualianeshop.service.CartService;
import com.gxa.hualianeshop.service.OrderItemService;
import com.gxa.hualianeshop.service.OrderService;
import com.gxa.hualianeshop.service.SkuService;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author bill
 * @since 2023-07-28
 */

@org.apache.dubbo.config.annotation.Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Reference
    CartService cartService;

    @Reference
    SkuService skuService;

    /**
     * 在当前服务中获取OrderItemService的bean对象
     */
    @Autowired
    OrderItemService orderItemService;


//    通过全局事务注解来管理分布式事务
    @GlobalTransactional
    @Override
    public String create(OrderDto orderDto) {

        //通过雪花算法生成订单编号
        long l = SnowFlake.nextId();
        String orderId = String.valueOf(l);

        // 引入消息队列
        // 生成一条消息( 异步订单 /  带有过期时间)

        // 创建订单

        // 获取用户的编号
        Long userId = orderDto.getUserId();

        // 先声明一个当前订单的总金额
        Long total = 0L;

        // 订单的金额是通过购物车中的勾选项统计合并生成
        // 生成订单项(order_item)的时候,通过查询购物车项信息,遍历添加
        List<Long> skuIdList = orderDto.getSkuIdList();
        for (Long skuId : skuIdList) {

            // 1.判断数据库中库存是否满足条件(加锁)
            // 2.查询指定商品的数量,同时加锁(for update)
            // 3.查询+判断条件是否符合(num -当前商品数量 >=0)
            // 4. 生成订单(订单项/订单状态/订单物流)
            // 1-4 必须事务方式实现, 事务结束, 才释放锁


            // 获取购物车中商品的小计
            CartItem cartItem = cartService.queryUserCartItem(userId, skuId);
            // 累加到订单的总金额中
            total += cartItem.getTotalPrice();

            // 生成订单项信息
            OrderItem orderItem = new OrderItem();
            // 通过雪花算法生成的订单编号
            orderItem.setOrderId(orderId);
            // 通过购物车项获取的商品的skuId
            orderItem.setSkuId(skuId);
            // 通过购物车中的商品数量生成订单项中的商品数量
            orderItem.setNum(cartItem.getNum());
            // 通过购物车中的商品单价生成订单项中的商品单价
            //最终通过数据库查询 skuService.get
            Sku byId = skuService.getById(skuId);
            orderItem.setPrice(byId.getPrice());


            // select num from tb_sku where sku_id= #{skuId} and num>=#{num} for update
            // 需要自定一个查询商品数量的方法,在添加订单前来给数据表skuId对应的记录加锁(行锁)
            Integer numById = skuService.getNumById(skuId, cartItem.getNum());
            //如果查询结果为空(或者库存为0), 表示库存不足, 下订单失败
            if(numById == null || numById==0){
                throw new BizException(ResultCode.ABSENT_NUM);
            }

            // 扣除商品库存 skuService
            // order+sku 横跨两个数据库, 在使用事务的时候? 要使用分布式事务 seata
            skuService.updateNumById(skuId,cartItem.getNum());

            // 通过触发异常来测试分布式事务
         //   int i = 1/0;


            // 完成了订单项的添加
            orderItemService.save(orderItem);

            // 删除购物车项
            cartService.removeCartItem(userId,skuId);

        }

        // 生成订单
        Order order = new Order();
        order.setOrderId(orderId);
        order.setTotalPay(total);
        order.setUserId(userId);
        this.save(order);

        // 生成订单状态
        OrderStatus orderStatus = new OrderStatus();

        // 生成订单的物流信息
        OrderShipping orderShipping = new OrderShipping();

        return orderId;
    }
}
